package org.opens.javaskill.design;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

/**
 * 说明:
 *      1. 这是建造者模式的demo.
 */
public class BuilderPattern {

    @Test
    public void testMealBuilder() {
        MealBuilder mealBuilder = new MealBuilder();
        Meal meal = mealBuilder.chickenBurgerAnd2BingFeng();
        meal.showItems();
        System.out.println(meal.getCost());
    }

    @Test
    public void testMealBuilder2() {
        Meal meal = MealBuilder2.builder().with(new ChickenBurger()).with(new Coke()).with(new Coke()).build();
        meal.showItems();
        System.out.println(meal.getCost());
    }

}

/**
 * 说明:
 *      1. 食品单位的父接口;
 * 功能:
 *      1. 可以使用ctrl + h来查看这个列的继承实现结构.
 */
interface Item {

    //食品名称
    public String name();

    //食品包装
    public Packing packing();

    //食品价格
    public float price();
}

/**
 * 说明:
 *      1. 包装方式的父接口.
 */
interface Packing {

    public String pack();

}

/**
 * 说明:
 *      1. 盒子包装.
 */
class Wrapper implements Packing {

    @Override
    public String pack() {
        return "Wrapper";
    }

}

/**
 * 说明:
 *      1. 瓶子包装.
 */
class Bottle implements Packing {

    @Override
    public String pack() {
        return "Bottle";
    }

}

/**
 * 说明:
 *      1. 汉堡包类食品的父类.
 */
abstract class Burger implements Item {

    @Override
    public Packing packing() {
        return new Wrapper();
    }

}

/**
 * 说明:
 *      1. 冷饮类的父类.
 */
abstract class ColdDrink implements Item {

    @Override
    public Packing packing() {
        return new Bottle();
    }

}

/**
 * 说明:
 *      1. 汉堡包的一个实现: 蔬菜汉堡包.
 */
class VegBurger extends Burger {

    @Override
    public String name() {
        return "Veg Burger";
    }

    @Override
    public float price() {
        return 30.0f;
    }

}

/**
 * 说明:
 *      1. 汉堡包的另一个实现: 鸡肉汉堡包.
 */
class ChickenBurger extends Burger {

    @Override
    public String name() {
        return "Chicken Burger";
    }

    @Override
    public float price() {
        return 50.0f;
    }

}

/**
 * 说明:
 *      1. 冷饮的一个实现类: 可口可乐.
 */
class Coke extends ColdDrink {

    @Override
    public String name() {
        return "Coke";
    }

    @Override
    public float price() {
        return 10.0f;
    }

}

/**
 * 说明:
 *      1. 冷饮的一个实现类: 冰峰.
 */
class BingFeng extends ColdDrink {

    @Override
    public String name() {
        return "Bing Feng";
    }

    @Override
    public float price() {
        return 2.5f;
    }

}

/**
 * 说明:
 *      1. 用户所点的菜单.
 */
class Meal {

    private List<Item> items = new ArrayList<>();

    public void addItem(Item item) {
        items.add(item);
    }

    public void addItems(List<Item> itemsTemp) {
        this.items.addAll(itemsTemp);
    }

    public void showItems() {
        for (int i = 0; i < items.size(); i++) {
            Item item = items.get(i);
            System.out.println(String.format("%d. %s, $%f, 包装: %s", i, item.name(), item.price(), item.packing().pack()));
        }
    }

    public float getCost() {
        float cost = 0.0f;
        for (Item item : items) {
            cost += item.price();
        }
        return cost;
    }

}

/**
 * 说明:
 *      1. 菜单构建方式1: 使用套菜形式.
 */
class MealBuilder {

    public Meal vegBurgerAndCoke() {
        Meal meal = new Meal();
        meal.addItem(new VegBurger());
        meal.addItem(new Coke());
        return meal;
    }

    public Meal chickenBurgerAnd2BingFeng() {
        Meal meal = new Meal();
        meal.addItem(new ChickenBurger());
        meal.addItem(new BingFeng());
        meal.addItem(new BingFeng());
        return meal;
    }

}

/**
 * 说明:
 *      1. 菜单构建形式二: 模拟链式写法构建动态菜单.
 */
class MealBuilder2 {

    public static MealBuildTemp builder() {
        return new MealBuildTemp();
    }

}

/**
 * 说明:
 *      1. 这个是菜单构建形式二中模拟链式写法构建动态菜单的一个中间类.
 */
class MealBuildTemp {

    private List<Item> items = new ArrayList<>();

    public MealBuildTemp with(Item item) {
        items.add(item);
        return this;
    }

    public Meal build() {
        Meal meal = new Meal();
        meal.addItems(items);
        return meal;
    }

}

